package com.zyy.jomap.resolve;

import com.zyy.jomap.util.StringUtil;

import java.io.File;
import java.io.FileFilter;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * OK--还未集成到ResolveJavaParser中
 * import中有使用.*的方式导入类的解析
 * import下的类名必须唯一
 * @author zhangyy
 */
public class MatchJava {

    /** 三方jar 包下的类缓存列表 key:com.common.bo, value:com.common.bo.User, com.common.bo.Project **/
    private static Map<String, List<String>> jarKeyClazzPathListMap=new HashMap<>();

    /** 无用 **/
    private static String resolveClassBuffer="";

    /**
     * 根据包路径获取包下的类文件路径
     * com.zyy.jomap.bo  file;
     * com.hoolink.iot.common.server.device.dmx  jar;
     * com.baomidou.mybatisplus.core.metadata  jar;
     * com.zyy.yjomapdemo.bo  无法使用该方式加载;
     * @param scannerPackage  包的模糊路径   com.hoolink.iot.common.server.*
     * @param clazzName    类名称
     */
    public static String parseClazzPath(String scannerPackage,String clazzName) {
        if(scannerPackage.startsWith("java")){
            //不解析java包下的类
            return null;
        }
        String packageName=scannerPackage.replace(".*","");
        if(checkIsProjectClazzPath(packageName)){
            addBuffer("project check ",Boolean.TRUE+"");
            //是当前项目中的类
            return getProjectClazzPath(packageName,clazzName);
        }

        String[] packageArr=scannerPackage.split("\\.");
        if(packageArr.length<3){
            return null;
        }
        String jarName=packageArr[0]+"."+packageArr[1]+"."+packageArr[2];
        List<String> clazzPathList=jarKeyClazzPathListMap.get(jarName);
        String clazzPath=getClazzPath(clazzPathList,packageName,clazzName);
        if(clazzPath!=null){
            //return clazzPath;
            addBuffer("cache match resolve clazz path",clazzPath);
            return clazzPath;
        }

        //缓存中不存在解析scannerPackage包
        try {
            Enumeration<URL> urls = MatchJava.class.getClassLoader().getResources(packageName.replace(".", "/"));
            while (urls.hasMoreElements()) {
                URL url = urls.nextElement();
                if (url != null) {
                    List<String> parseClazzPathList=new ArrayList<>();
                    String protocol = url.getProtocol();
                    if (protocol.equals("file")) {
                        //本项目的文件包
                        // 转码
                        String packagePath = URLDecoder.decode(url.getFile(), "UTF-8");
                        // JAVA文件
                        parseProjectSelfJavaFile(packagePath, packageName,parseClazzPathList);
                    } else if (protocol.equals("jar")) {
                        //jar包中的包
                        JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
                        if (jarURLConnection != null) {
                            JarFile jarFile = jarURLConnection.getJarFile();
                            if (jarFile != null) {
                                Enumeration<JarEntry> jarEntries = jarFile.entries();
                                //遍历jar中的所有包和文件
                                while (jarEntries.hasMoreElements()) {
                                    JarEntry jarEntry = jarEntries.nextElement();
                                    String jarEntryName = jarEntry.getName();
                                    if (jarEntryName.endsWith(".class")) {
                                        String parseClazzName = jarEntryName.substring(0, jarEntryName.lastIndexOf("."))
                                                .replaceAll("/", ".");
                                        parseClazzPathList.add(parseClazzName);
                                    }
                                }
                            }
                        }
                    }
                    //缓存解析后的类信息
                    jarKeyClazzPathListMap.put(jarName,parseClazzPathList);
                    clazzPath=getClazzPath(parseClazzPathList,packageName,clazzName);
                    addBuffer("match resolve clazz path",clazzPath);
                    if(clazzPath!=null){
                        return clazzPath;
                    }
                }
            }
        }catch(Exception e){
            e.printStackTrace();
            addBuffer("error",e.getMessage());
        }
        return null;
    }

    /**
     * 检验是否为当前项目的类
     * @param packageName  包路径 com.zyy.jomap.bo
     * @return true:项目中的类文件, false:三方jar包中的类文件
     */
    public static boolean checkIsProjectClazzPath(String packageName){
        String packageAbsPath=ResolveJava.getPackageAbsPath(packageName);

        addBuffer("packageAbsPath ",packageAbsPath);

        File packageFile=new File(packageAbsPath);
        if(packageFile.exists()){
            return true;
        }else{
            return false;
        }
    }

    /**
     * 获取当前项目包下的类路径--解析com.zyy.jomap.*下的类
     * @param packageName  包路径:com.zyy.jomap
     * @param clazzName  类名:UserBO
     * @return  com.zyy.jomap.bo.UserBO
     */
    public static String getProjectClazzPath(String packageName,String clazzName){
        String packageAbsPath=ResolveJava.getPackageAbsPath(packageName);
        addBuffer("getProjectClazzPath ",packageName);
        File[] packageFileList=new File(packageAbsPath).listFiles(new FileFilter() {
            @Override
            public boolean accept(File file) {
                return (file.isFile() && file.getName().endsWith(".java") || file.isDirectory());
            }
        });
        for(File file:packageFileList){
            if(file.isFile()&&clazzName.equals(StringUtil.removeExtName(file.getName()))){
                return packageName+"."+clazzName;
            }else if(file.isDirectory()){
                packageName=packageName+"."+file.getName();
                return getProjectClazzPath(packageName,clazzName);
            }
        }
        return null;
    }

    /**
     * 解析项目自身的JAVA文件
     * @param packagePath  包绝对路径:E:/iot-workspace/jomap/com/zyy/jomap
     * @param packageName  包名:com.zyy.jomap
     * @param parseClazzPathList 包下的类路径列表:com.zyy.jomap.bo.UserBO,com.zyy.jomap.bo.User
     * @return void
     * @throws
     */
    private static void parseProjectSelfJavaFile(String packagePath, String packageName,List<String> parseClazzPathList) {
        File[] files = new File(packagePath).listFiles(new FileFilter() {
            @Override
            public boolean accept(File file) {
                return (file.isFile() && file.getName().endsWith(".class") || file.isDirectory());
            }
        });
        for (File file : files) {
            String fileName = file.getName();
            if (file.isFile()) {
                String clazzName = fileName.substring(0, fileName.lastIndexOf("."));
                if (packageName!=null) {
                    clazzName = packageName + "." + clazzName;
                }
                parseClazzPathList.add(clazzName);
            } else {
                // 子目录
                String subPackagePath = fileName;
                if (packagePath!=null) {
                    subPackagePath = packagePath + "/" + subPackagePath;
                }
                String subPackageName = fileName;
                if (packageName!=null) {
                    subPackageName = packageName + "." + subPackageName;
                }
                parseProjectSelfJavaFile(subPackagePath, subPackageName,parseClazzPathList);
            }
        }
    }

    /**
     * 获取类的包路径
     * @param clazzPackagePathList
     * @param packageName
     * @param clazzName
     * @return
     */
    private static String getClazzPath(List<String> clazzPackagePathList,String packageName,String clazzName){
        if(clazzPackagePathList!=null&&clazzPackagePathList.size()>0){
            for(String clazzPath:clazzPackagePathList){
                if(clazzPath.startsWith(packageName)&&clazzPath.endsWith(clazzName)){
                    return clazzPath;
                }
            }
            return null;
        }else{
            return null;
        }
    }

    /**
     * 打印解析信息
     */
    public static void printResolveMsg(){
        GenerateMapFile.doGenerateClassFile(resolveClassBuffer,"com.zyy.jomap.convert.test");
    }

    /**
     * 记录要打印的信息
     * @param tip
     * @param content
     */
    public static void addBuffer(String tip,String content){
        resolveClassBuffer+=tip+"==================>"+content+"\r\n";
    }

}
